
package com.tsh.core.mp.base;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsh.core.launch.constant.AppConstant;
import com.tsh.core.secure.TshUser;
import com.tsh.core.secure.utils.AuthUtil;
import com.tsh.core.tool.constant.TshConstant;
import com.tsh.core.tool.utils.BeanUtil;
import lombok.SneakyThrows;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 业务封装基础类
 *
 * @param <M> mapper
 * @param <T> model
 * @author Mosj
 */
@Validated
public class CommonServiceImpl<M extends BaseMapper<T>, T extends CommonEntity> extends ServiceImpl<M, T> implements CommonService<T> {

	@Override
	public boolean save(T entity) {
		this.resolveEntity(entity);
		return super.save(entity);
	}

	@Override
	public boolean saveBatch(Collection<T> entityList, int batchSize) {
		entityList.forEach(this::resolveEntity);
		return super.saveBatch(entityList, batchSize);
	}

	@Override
	public boolean updateById(T entity) {
		this.resolveEntityInternal(entity, false);
		return super.updateById(entity);
	}

	@Override
	public boolean updateBatchById(Collection<T> entityList, int batchSize) {
		entityList.forEach(entity -> resolveEntityInternal(entity,false));
		return super.updateBatchById(entityList, batchSize);
	}

	@Override
	public boolean saveOrUpdate(T entity) {
		if (entity.getId() == null) {
			return this.save(entity);
		} else {
			if(this.baseMapper.exists(new QueryWrapper<T>().setEntityClass((Class<T>) entity.getClass()).lambda().eq(CommonEntity::getId, entity.getId()))){
				return this.updateById(entity); //记录存在，更新
			}
			else{
				return this.save(entity);//记录不存在，插入
			}
		}
	}

	@Override
	public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
		entityList.forEach(this::resolveEntity);
		return super.saveOrUpdateBatch(entityList, batchSize);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean deleteLogic(@NotEmpty List<Long> ids) {
		TshUser user = AuthUtil.getUser();
		List<T> list = new ArrayList<>();
		LocalDateTime now = LocalDateTime.now();
		ids.forEach(id -> {
			T entity = BeanUtil.newInstance(currentModelClass());
			if (user != null) {
				entity.setUpdateUserId(user.getUserId() == null ? null : user.getUserId());
				entity.setUpdateUserName(user.getNickName());
			}
			entity.setUpdateDate(now);
			entity.setId(id);
			list.add(entity);
		});
		return super.updateBatchById(list) && super.removeByIds(ids);
	}

	/**
	 * 为新增或者更新的属性设置默认值
	 * 如：创建人、创建时间、更新人、更新时间
	 */
	@SneakyThrows
	@Override
	public void resolveEntity(CommonEntity entity) {
		resolveEntityInternal(entity, true);
	}

	/**
	 * 为新增或者更新的属性设置默认值
	 * 如：创建人、创建时间、更新人、更新时间
	 */
	private void resolveEntityInternal(CommonEntity entity, boolean isAdd) {
		if(entity == null){
			return;
		}
		TshUser user = AuthUtil.getUser();
		LocalDateTime now = LocalDateTime.now();

		if(isAdd) {
			if (entity.getId() != null) {
				//id在数据库不存在记录，表示新增，否则更新
				isAdd = !this.baseMapper.exists(new QueryWrapper<T>().setEntityClass((Class<T>) entity.getClass()).lambda().eq(CommonEntity::getId, entity.getId()));
			}
		}

		if (isAdd) {
			// 处理新增逻辑
			if (user != null) {
				entity.setCreateUserId(user.getUserId() == null ? null : user.getUserId());
				entity.setCreateUserName(user.getNickName());
			}
			else{
				entity.setCreateUserId(AppConstant.ADMIN_ID);
				entity.setCreateUserName(AppConstant.ADMIN_CH_NAME);
			}
			entity.setCreateDate(now);
			entity.setRecordFlag(TshConstant.RECORD_NORMAL);
		}

		// 处理通用逻辑
		if (user != null) {
			entity.setUpdateUserId(user.getUserId() == null ? null : user.getUserId());
			entity.setUpdateUserName(user.getNickName());
		}
		else{
			entity.setUpdateUserId(AppConstant.ADMIN_ID);
			entity.setUpdateUserName(AppConstant.ADMIN_CH_NAME);
		}
		entity.setUpdateDate(now);
	}

}
